
#include "precompiled.h"
#include "plugins.h"

#include <extensions/plugin.h>
#include "nativeplugin.h"
#include "scriptplugin.h"
#include "declarativeextension.h"

#include "helper.h"
#include <extensions/context.h>
#include "script/contextimpl.h"

using Optra::Extensions::ContextPtr;

Optra::Extensions::Plugin* Plugins::fromFile(const QString& filename)
{
    LI.Debug() << "Load plugin:" << filename;


    QFileInfo finfo(filename);

    if (!finfo.exists()|| !finfo.isReadable()){
        LI.Warning() << "Plugin don't exists, or permissions denied file:" << filename;
        return 0;
    }

    ContextPtr ctx = new ContextImpl(0);
    ctx->process(finfo.absoluteDir());

    QString ext = finfo.suffix().toLower();

    if (ext == Optra::Extensions::Plugin::ExtDeclarativeExtension){
        return new DeclarativeExtension(Optra::Extensions::Plugin::extension, ctx, finfo);
    }

    if (ext == Optra::Extensions::Plugin::ExtDeclarativeApplication){
        return new DeclarativeExtension(Optra::Extensions::Plugin::application, ctx, finfo);
    }

    if (ext == Optra::Extensions::Plugin::ExtScriptExtension){
        return new ScriptPlugin(Optra::Extensions::Plugin::extension, ctx, finfo);
    }

    if (ext == Optra::Extensions::Plugin::ExtScriptApplication){
        return new ScriptPlugin(Optra::Extensions::Plugin::application, ctx, finfo);
    }

    if (ext == Optra::Extensions::Plugin::ExtNativeExtension){
        return new NativePlugin(Optra::Extensions::Plugin::extension, ctx, finfo);
    }

    if (ext == Optra::Extensions::Plugin::ExtNativeApplication || ext.compare(QLatin1String("dll")) == 0){
        return new NativePlugin(Optra::Extensions::Plugin::application, ctx, finfo);
    }

    LI.Warning() << "Invalid plugin type file:" << filename;
    return 0;
}

class PluginsPrivate{
public:
    PluginsPrivate() {}
    ~PluginsPrivate() {}

    QMap<Optra::Extensions::Plugin::Area, Optra::Extensions::Plugin*> plugins;

    void processDirectory(QDir& dir)
    {

        LI.Info() << "Processing direcotry:" << dir.absolutePath();
        QStringList masks;
        masks
                << "*." + Optra::Extensions::Plugin::ExtDeclarativeExtension
                << "*." + Optra::Extensions::Plugin::ExtDeclarativeApplication
                << "*." + Optra::Extensions::Plugin::ExtScriptExtension
                << "*." + Optra::Extensions::Plugin::ExtScriptApplication
                << "*." + Optra::Extensions::Plugin::ExtNativeExtension
                << "*." + Optra::Extensions::Plugin::ExtNativeApplication;

        foreach (QString file, dir.entryList(masks))
        {
            QString fileName = dir.absoluteFilePath(file);
            LI.Debug() << "Processing file:" << fileName;

            Optra::Extensions::Plugin* plugin = Plugins::fromFile(fileName);
            if (plugin == 0){
                LI.Warning() << "Null reference plugin";
                continue;
            }

            if (!plugin->valid()){
                LI.Warning() << "error loading plugin:" << plugin->errorString();
                delete plugin;
                continue;
            }

            LI.Debug() << "Plugin loaded";
            //plugin->start();
            plugins.insert(plugin->area(), plugin);
        }
    }

};

Plugins::Plugins(QObject *parent) :
    QObject(parent), O_PRIVATE_CREATE(Plugins)
{
    O_D(Plugins);
    //d->
}

Plugins::~Plugins()
{
    O_PRIVATE_DELETE;
}



void Plugins::load(const ContextPtr& ctx)
{
    O_D(Plugins);
    QDir root = ctx->rootDir();
    if (!root.cd("extensions"))
        return;
    foreach (QString dirname, root.entryList(QDir::Dirs | QDir::NoDotAndDotDot | QDir::Readable))
    {
        root.cd(dirname);
        d->processDirectory(root);
        root.cdUp();
    }

}
